package java_thinking.unit_17._17_9_10;

import java.util.List;

/**
 * @Desc:   Tester.run()方法调用适当的重载构造器，然后调用timedTest()，它汇之星针对该容器的列表中的每一个测试
 *          timedTest()会使用paramList中的每个TestParam对象进行重复测试，因为paramList是从静态的defaultParams
 *          数组中初始化出来的，因此可以通过重新赋值defaultParams来修改用于所有测试的paramList,或者可以通过传递
 *          针对某个测试的定制的paramList,来修改用于该测试的paramList
 * @author: cww
 * @DateTime: 2019-04-20 22:44
 */

public class Tester<C> {
    public static int fieldWidth = 8;
    public static TestParam[] defaultParams = TestParam.array(10,5000,100,5000,1000,5000,10000,500);
    protected C initialize(int size) {
        return container;
    }
    protected C container;
    private String headline = "";
    private List<Test<C>> tests;

    /**
     * 用于输出结果的格式化字符串，格式化的标准宽度可以通过修改静态的fieldWidth的值进行调整
     * @return
     */
    private static String stringField() {
        return "%" + fieldWidth + "s";
    }
    private static String numberField() {
        return "%" + fieldWidth + "d";
    }
    private static int sizeWidth = 5;
    private static String sizeField = "%" + sizeWidth + "s";
    private TestParam[] paramList = defaultParams;

    public Tester(C container,List<Test<C>> tests) {
        this.container = container;
        this.tests = tests;
        if (container != null) {
            headline = container.getClass().getSimpleName();
        }
    }

    public Tester(C container, List<Test<C>> tests, TestParam[] paramList) {
        this(container,tests);
        this.paramList = paramList;
    }

    public void setHeadline(String headline) {
        this.headline = headline;
    }
    public static <C> void run(C cntnr,List<Test<C>> tests) {
        new Tester<C> (cntnr,tests).timedTest();
    }

    public static <C> void run(C cntnr,List<Test<C>> tests,TestParam[] paramList) {
        new Tester<C> (cntnr,tests,paramList).timedTest();
    }

    /**
     * 为方法每个测试格式化和打印头信息
     */
    private void displayHeader() {
        int width = fieldWidth * tests.size() + sizeWidth;
        int dashLength = width - headline.length() -1;
        StringBuilder head = new StringBuilder(width);
        for (int i =0; i < dashLength/2; i++) {
            head.append('-');
        }
        head.append(' ');
        head.append(headline);
        head.append(' ');
        for (int i = 0; i < dashLength/2; i++) {
            head.append('-');
        }
        System.out.println(head);
        System.out.format(sizeField,"size");
        for (Test test : tests) {
            System.out.format(stringField(),test.name);
        }
        System.out.println();
    }

    /**
     * 计时每个任务耗时
     */
    public void timedTest() {
        displayHeader();
        for (TestParam param : paramList) {
            System.out.format(sizeField,param.size);
            for (Test<C> test : tests) {
                C kontainer = initialize(param.size);
                long start = System.nanoTime();
                int reps = test.test(kontainer,param);
                long duration = System.nanoTime() - start;
                long timePerRep = duration / reps;
                System.out.format(numberField(),timePerRep);
            }
            System.out.println();
        }
    }

}
